#ifndef HASHBOX_H_JM_20120910
#define HASHBOX_H_JM_20120910

#include "../RootBox.h"
#include "BoxStaticHashTableWrapper.h"
#include "../../common/hash/BoostHashWrapper.h"
#include "../../common/Utils.h"

#include <bobox_box.hpp>
#include <bobox_types.hpp>

#include <sstream>

namespace jm4bbx {

	struct HashBoxDescriptor {
		static const  groupType INPUT_GROUP;
		//static const  groupTypeOUTPUT_GROUP;	
		static const  columnType INPUT_COLUMN;
		//static const  columnType OUTPUT_COLUMN;
		static const  inType IN_ARC;
		//static const  bobox::outarc_index_type OUT_ARC;
		
	};

	//struct IntegerHashBoxDescriptor : public HashBoxDescriptor {
	//	//static const char* BOX_ID;
	//};

	//struct StringHashBoxDescriptor : public HashBoxDescriptor {
	//	//static const char* BOX_ID;
	//};

	template<class policyT, /*class BoxDescriptor,*/ size_t TABLE_SIZE = 100>
	class  HashBox : public Box/*<BoxDescriptor>*/ {
		
	public:
		typedef HashBoxDescriptor BoxIO;

		static const size_t HASH_TABLE_SIZE = TABLE_SIZE;
		
		typedef policyT policyType;
		typedef typename policyType::value_type valueType;

		typedef BoxStaticHashTableWrapper<valueType, valueType, HASH_TABLE_SIZE> 
			StaticHashTableHolderType;

		HashBox(bobox::box_id_type id, bobox::box_tid_type tid, 
			bobox::request *req, const bobox::parameters &params) 
			: Box(id, tid, req, params) { }

		virtual void initImpl() {

			add_group(BoxIO::INPUT_GROUP, 
				BoxIO::INPUT_COLUMN, 
				get_input_descriptors(BoxIO::IN_ARC));

			//add_group(BoxIO::OUTPUT_GROUP, 
			//	BoxIO::OUTPUT_COLUMN, 
			//	get_output_descriptors(BoxIO::OUT_ARC));

			wait4Receive();
		}

		virtual void sync_mach_etwas() {

			Group ig = get_group(BoxIO::INPUT_GROUP);
			if (ig.isPoisoned()/*poisoned_*/) {
				//send_poisoned(BoxIO::OUT_ARC);
				return;
			}

			const int rpos = ig.getReadPosition();//rdpos_;
			const int rend = ig.getReadEnd();//rdend_;

			BoostHashWrapper<valueType> hash;


			tableHolder_.getHashTable()->setSynchronized(true);

			//for (; ig.rdpos_ < ig.rdend_; ++ig.rdpos_) {
			for (; ig.getReadPosition() < ig.getReadEnd(); ig.moveReadPosition()) {				
				std::stringstream stream;

				stream << "hash_box id:" << getBoxInstanceId() << " hashuje ";
				auto key = get_data<policyT>(BoxIO::INPUT_COLUMN)[ig.getReadPosition()/*rdpos_*/];
				auto value = key + "~~" + stream.str();
				int count = tableHolder_.getHashTable()->add(key, key);

				stream << key << "-> #"<< count << std::endl;
				std::cout <<  stream.str(); 
			}

			//const group& og = get_group(BoxIO::OUTPUT_GROUP);

			//og.wrbegin_ = rpos;
			//og.wrpos_ = rend;
			//og.wrend_ = rend;

			//send(BoxIO::OUT_ARC, BoxIO::OUTPUT_GROUP);
			sendSignalsOut();
			wait4Receive();
		}
	private:
		
		StaticHashTableHolderType tableHolder_;

		void wait4Receive() {
			wait4SignalsIn();
			receive(BoxIO::IN_ARC, BoxIO::INPUT_GROUP);
		}
	};


	class IntegerHashBox : 
		public HashBox<bobox::int_policy/*, IntegerHashBoxDescriptor*/> {
	public:
		IntegerHashBox(bobox::box_id_type id, bobox::box_tid_type tid, 
			bobox::request *req, const bobox::parameters &params) 
			: HashBox(id, tid, req, params) { }
	}; 

	class StringHashBox : 
		public HashBox<bobox::string_policy/*, StringHashBoxDescriptor*/> {
	public:
		StringHashBox(bobox::box_id_type id, bobox::box_tid_type tid, 
			bobox::request *req, const bobox::parameters &params) 
			: HashBox(id, tid, req, params) { }

	}; 

} // namespace jm4bbx


#endif
